import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from sql_compiler.lexer import Lexer
from sql_compiler.parser import Parser
from sql_compiler.planner import Planner, PlanNodeType, PlanNode
from sql_compiler.parser import ASTNodeType, ASTNode
from engine.catalog_manager import CatalogManager
from engine.storage_engine import StorageEngine
from engine.executor import Executor

class DatabaseCLI:
    def __init__(self):
        self.catalog_manager = CatalogManager()
        self.storage_engine = StorageEngine()
        self.executor = Executor(self.catalog_manager, self.storage_engine)
        # 语义分析器当前与 CatalogManager 接口不一致，先跳过
        self.semantic_analyzer = None
        self.planner = Planner()
        
        # 当前数据库状态
        self.current_db = None
    
    def execute_sql(self, sql: str):
        """执行SQL语句"""
        try:
            # 词法分析
            lexer = Lexer(sql)
            tokens = lexer.tokenize()
            
            # 语法分析
            parser = Parser(tokens)
            ast = parser.parse()
            
            # 语义分析
            # 若有语义分析器且可用，执行语义分析；否则直接使用AST
            analyzed_ast = ast if self.semantic_analyzer is None else self.semantic_analyzer.analyze(ast) or ast

            # 生成执行计划（可能包含多条）
            plans = self.planner.plan(analyzed_ast)

            # 逐个执行计划节点（仅针对已实现的操作）
            for plan in plans:
                if plan.node_type == PlanNodeType.CREATE_TABLE:
                    table_info = plan.properties.get("table_info")
                    result = self.executor.execute_create_table(table_info)
                    print("Table created successfully" if result else "Error: Table already exists")
                elif plan.node_type == PlanNodeType.INSERT:
                    table_name = plan.properties.get("table_name")
                    values = plan.properties.get("values", [])
                    # 获取表信息以验证列数
                    table_info = self.catalog_manager.get_table(table_name)
                    if table_info and len(values) == len(table_info.columns):
                        result = self.executor.execute_insert(table_name, values)
                        print("Record inserted successfully" if result else "Insert failed")
                    else:
                        print(f"Error: Column count mismatch. Expected {len(table_info.columns) if table_info else 'unknown'}, got {len(values)}")
                elif plan.node_type in (PlanNodeType.PROJECT, PlanNodeType.SEQ_SCAN, PlanNodeType.FILTER):
                    # 从计划树根部解析 SELECT 的执行参数
                    table_name, columns, condition_func = self._extract_select_params(plan)
                    records = self.executor.execute_select(table_name, columns, condition_func)
                    if records:
                        headers = list(records[0].keys())
                        print("\t".join(headers))
                        print("-" * 20)
                        for record in records:
                            values_out = [str(record[col]) for col in headers]
                            print("\t".join(values_out))
                        print(f"\n{len(records)} row(s) returned")
                    else:
                        print("No rows returned")
                elif plan.node_type == PlanNodeType.DELETE:
                    # 解析 DELETE 的执行参数
                    table_name, _, condition_func = self._extract_select_params(plan.children[0] if plan.children else plan)
                    count = self.executor.execute_delete(table_name, condition_func)
                    print(f"{count} row(s) deleted")
                else:
                    print(f"Unsupported operation: {plan.node_type}")

        except Exception as e:
            print(f"Error: {e}")

    def _extract_select_params(self, plan: PlanNode):
        """从计划树中提取 SELECT/DELETE 需要的 table_name、columns、condition_func。"""
        # 默认值
        table_name = None
        columns = ["*"]
        condition_func = None

        # 深度优先遍历
        stack = [plan]
        while stack:
            node = stack.pop()
            if node.node_type == PlanNodeType.SEQ_SCAN:
                table_name = node.properties.get("table_name")
            elif node.node_type == PlanNodeType.PROJECT:
                columns = node.properties.get("columns", ["*"])
            elif node.node_type == PlanNodeType.FILTER:
                condition_ast = node.properties.get("condition_ast")
                if condition_ast is not None:
                    condition_func = self._build_condition_func(condition_ast)
            # 遍历子节点
            for child in node.children:
                stack.append(child)
        return table_name, columns, condition_func

    def _build_condition_func(self, expr: ASTNode):
        """将简单的表达式 AST 转换为可执行的布尔函数。支持 =, <, >, <=, >=, <>。"""
        def eval_expr(node: ASTNode, row: dict):
            if node.node_type == ASTNodeType.COLUMN_REF:
                return row.get(node.value)
            if node.node_type == ASTNodeType.VALUE:
                return node.value
            if node.node_type == ASTNodeType.BINARY_OP:
                left = eval_expr(node.children[0], row)
                right = eval_expr(node.children[1], row)
                op = node.value
                # TokenType 的 value 是枚举名称，例如 'EQUALS'、'GREATER_THAN' 等
                symbol = getattr(op, 'value', str(op))
                if symbol == 'EQUALS':
                    return left == right
                if symbol == 'NOT_EQUALS':
                    return left != right
                if symbol == 'LESS_THAN':
                    return left < right
                if symbol == 'GREATER_THAN':
                    return left > right
                if symbol == 'LESS_EQUALS':
                    return left <= right
                if symbol == 'GREATER_EQUALS':
                    return left >= right
                return False
            return False

        return lambda row: bool(eval_expr(expr, row))
    
    def run(self):
        """运行CLI"""
        print("Simple Database System CLI,欢迎")
        print("Type 'exit' to quit")
        
        while True:
            try:
                # 读取输入
                command = input("db> ").strip()
                
                if command.lower() == 'exit':
                    break
                
                if not command:
                    continue
                
                # 执行SQL
                self.execute_sql(command)
                
            except KeyboardInterrupt:
                print("\nUse 'exit' to quit")
            except Exception as e:
                print(f"Error: {e}")

if __name__ == "__main__":
    cli = DatabaseCLI()
    cli.run()